<template>
  <div class="Echarts">
    <div
      :id="uiOptions.chartId"
      :style="'width:' + uiOptions.chartWidth + 'px ;height: 300px'"
    />
  </div>
</template>

<script setup lang="ts">
import { onMounted, reactive, watch } from "vue";
import { Ingress, Service, useK8SApi } from "../../../api/k8s";
import { init } from "echarts";
import { useRouter } from "vue-router";
import { KubeHudRouterPath } from "../../../router";

const { serviceRepo, podRepo } = useK8SApi();
const router = useRouter();

type Prop = {
  namespace?: string;
  cluster?: string;
};

const props = defineProps<Prop>();
const ingressObject = defineModel<Ingress>("ingressObject");

const uiOptions = reactive({
  chartView: null,
  chartWidth: window.innerWidth,
  chartId: `${props.cluster}|${props.namespace}|${ingressObject.value?.metadata?.name ?? "-"}|ingress|relationship-chart`
});

const getServiceNodes = async (): Promise<{
  linkDataArray: any[];
  nodes: any[];
  serviceNodes: any[];
}> => {
  const nodeRes = {
    linkDataArray: [],
    nodes: [],
    serviceNodes: []
  };

  const rules = ingressObject.value?.spec?.rules ?? [];

  // 获取所有http服务service名称
  const httpSvrNames = rules
    .flatMap(rule => rule.http?.paths ?? [])
    .map(path => path.backend?.service?.name)
    .filter(name => name && name !== "");

  // 去重
  const uqNames = [...new Set(httpSvrNames)];

  // 获取service详情列表
  const serviceList = await Promise.all([
    ...uqNames.map(name =>
      serviceRepo.getServiceDetail({
        clusterName: props.cluster,
        namespace: props.namespace,
        name
      })
    )
  ]);

  // 生成service节点
  serviceList.forEach(service => {
    if (!service) return;
    nodeRes.nodes.push({
      name: `Service ${service.metadata.namespace}.${service.metadata.name}`,
      itemStyle: { color: "#ff9900" },
      draggable: true,
      symbolSize: [50, 50],
      nodeType: "Service",
      nodeName: service.metadata.name,
      nodeNameSpace: service.metadata.namespace
    });

    nodeRes.linkDataArray.push({
      source: `Ingress ${props.namespace}.${ingressObject.value?.metadata?.name}`,
      target: `Service ${service.metadata.namespace}.${service.metadata.name}`,
      symbol: ["circle", "arrow"],
      symbolSize: [5, 5]
    });

    nodeRes.serviceNodes.push(service);
  });

  return nodeRes;
};

const getPodNodes = async (
  services?: Service[]
): Promise<{
  linkDataArray: any[];
  nodes: any[];
  podsNodes: any[];
}> => {
  const podListGroup = await Promise.all([
    ...services?.map(service =>
      podRepo.getPodList({
        clusterName: props.cluster,
        namespace: service.metadata.namespace,
        labelSelector: `app=${service.metadata.name}`
      })
    )
  ]);

  const podRes = {
    linkDataArray: [],
    nodes: [],
    podsNodes: []
  };

  podListGroup.forEach(podList => {
    if (!podList) return;
    podList.items.forEach(pod => {
      podRes.nodes.push({
        name: `Pod ${pod.metadata.namespace}.${pod.metadata.name}`,
        itemStyle: { color: "#0099ff" },
        draggable: true,
        symbolSize: [50, 50],
        nodeType: "Pod",
        nodeName: pod.metadata.name,
        nodeNameSpace: pod.metadata.namespace
      });

      podRes.linkDataArray.push({
        source: `Service ${pod.metadata.namespace}.${pod.metadata.name}`,
        target: `Pod ${pod.metadata.namespace}.${pod.metadata.name}`,
        symbol: ["circle", "arrow"],
        symbolSize: [5, 5]
      });

      podRes.podsNodes.push(pod);
    });
  });

  return podRes;
};

const initCharts = async () => {
  const chartDom = document.getElementById(uiOptions.chartId);
  if (!chartDom) return;

  // 初始化页面
  uiOptions.chartView = init(chartDom);

  const defaultChartData = {
    nodes: [
      {
        name: `Ingress ${props.namespace}.${ingressObject.value?.metadata?.name}`,
        itemStyle: { color: "#0099ff" },
        draggable: true,
        symbolSize: [50, 50]
      }
    ],
    linesData: []
  };

  const svrRes = await getServiceNodes();
  defaultChartData.nodes = [...defaultChartData.nodes, ...svrRes.nodes];
  defaultChartData.linesData = [
    ...defaultChartData.linesData,
    ...svrRes.linkDataArray
  ];

  const podRes = await getPodNodes(svrRes.serviceNodes);

  defaultChartData.nodes = [...defaultChartData.nodes, ...svrRes.serviceNodes];
  defaultChartData.linesData = [
    ...defaultChartData.linesData,
    ...podRes.linkDataArray
  ];

  const chartOptions = {
    backgroundColor: "#ccc",
    tooltip: {
      formatter: params => {
        if (params.dataType === "edge") {
          return params.data?.target;
        } else {
          return params.data?.name;
        }
      }
    },
    series: [
      {
        type: "graph",
        top: "10%",
        roam: true,
        focusNodeAdjacency: true,
        force: { repulsion: 100, edgeLength: [150, 100] },
        layout: "force",
        symbol: ["rect", "arrow"],
        lineStyle: {
          normal: {
            color: "#000",
            width: 1,
            type: "solid",
            opacity: 0.5,
            curveness: 0
          }
        },
        label: {
          normal: {
            show: true,
            position: "inside",
            textStyle: { fontSize: 16 }
          }
        },
        edgeLabel: {
          normal: { show: false, textStyle: { fontSize: 14 } }
        },
        data: defaultChartData.nodes,
        links: defaultChartData.linesData
      }
    ],
    animationEasingUpdate: "quinticInOut",
    animationDurationUpdate: 100
  };

  uiOptions.chartView.setOPtion(chartOptions);
  uiOptions.chartView?.on("click", params => {
    if (params.dataType == "node") {
      if (params.data.nodeType == "Pod") {
        router.push({
          name: KubeHudRouterPath.PodDetails, // "PodDetail",
          params: {
            name: params.data.nodeName,
            namespace: params.data.nodeNamespace
          },
          query: { yamlShow: "false" }
        });
      }
      if (params.data.nodeType == "Service") {
        router.push({
          name: KubeHudRouterPath.ServiceDetails, // "ServiceDetail",
          params: {
            name: params.data.nodeName,
            namespace: params.data.nodeNamespace
          },
          query: { yamlShow: "false" }
        });
      }
    }
  });
};

watch(
  () => props.cluster,
  (nv, ov) => {
    if (nv !== ov) {
      initCharts();
    }
  }
);

watch(
  () => props.namespace,
  (nv, ov) => {
    if (nv !== ov) {
      initCharts();
    }
  }
);

watch(
  () => ingressObject.value,
  (nv, ov) => {
    if (nv !== ov) {
      initCharts();
    }
  }
);

onMounted(() => {
  initCharts();
});
</script>

<style scoped></style>
